fix(webapp): allow JWT auth on POST /api/v1/sessions#3474
Conversation
The route was secret-key-only by design ("Customer's server owns session creation"). That holds for the customer browser path — `chat.createStartSessionAction` runs server-side and authorizes there. But the cli-v3 MCP `start_agent_chat` tool is itself a server-side surface (developer's CLI/IDE acting as their own server) and only holds a JWT minted from the user's PAT. Without JWT support here it can't create sessions, blocking the entire MCP agent toolkit.
Add `allowJWT: true` and an `authorization` block requiring the `write:sessions` (or `admin`) super-scope. Resource scoping by `taskIdentifier` isn't possible at auth-resolve time — action routes don't pass `body` to the resource callback, and the task name only lives in the body — so the resource is a `sessions` wildcard and the super-scope does the gating. The JWT-issuer (cli-v3 MCP, customer servers wrapping a wider auth helper, etc.) decides which scopes to mint, which is where per-task narrowing lives.
Verified end-to-end: `mcp__trigger__start_agent_chat` → `send_agent_message("pong")` → `send_agent_message("echo")` → `close_agent_chat` all succeed against local. Two assistant turns reuse the same runId (continuation in the idle window).
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
🧰 Additional context used📓 Path-based instructions (7)**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
{packages/core,apps/webapp}/**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.ts📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
Files:
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.ts{,x}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
apps/webapp/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Files:
🧠 Learnings (14)📚 Learning: 2026-03-13T13:42:59.104ZApplied to files:
📚 Learning: 2026-04-13T21:44:00.032ZApplied to files:
📚 Learning: 2026-02-25T17:28:20.456ZApplied to files:
📚 Learning: 2026-04-20T15:05:59.661ZApplied to files:
📚 Learning: 2026-04-16T13:45:22.317ZApplied to files:
📚 Learning: 2026-04-20T15:06:11.054ZApplied to files:
📚 Learning: 2026-04-16T14:21:11.115ZApplied to files:
📚 Learning: 2026-03-10T17:56:26.581ZApplied to files:
📚 Learning: 2026-02-11T16:50:14.167ZApplied to files:
📚 Learning: 2025-08-14T10:53:54.526ZApplied to files:
📚 Learning: 2026-03-26T09:02:11.935ZApplied to files:
📚 Learning: 2026-02-19T18:09:23.944ZApplied to files:
📚 Learning: 2026-03-22T13:26:12.060ZApplied to files:
📚 Learning: 2026-03-22T19:24:14.403ZApplied to files:
🔇 Additional comments (1)
WalkthroughThe session creation Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
Devin caught two real issues with the previous resource shape on PR #3474: 1. The "body isn't available at auth-resolve time" claim was wrong. Action-route resource callbacks receive the parsed body as the 4th arg (apiBuilder.server.ts:710). Other routes like api.v1.tasks.batch.ts use it (line 33). 2. The auth check is OR across resource types — listing both `sessions: "*"` and `tasks: body.taskIdentifier` would let a `write:sessions`-only JWT pass for any task, defeating the per-task narrowing. Replace `() => ({ sessions: "*" })` with `(_, __, ___, body) => ({ tasks: body.taskIdentifier })` and rely on the `write:sessions` / `admin` super-scopes for broad access. A JWT scoped only to `write:tasks:foo` can now only create sessions whose taskIdentifier is `foo`. MCP-style flows that hold `write:sessions` continue to work via the super-scope path. Verified: MCP `start_agent_chat` → `send_agent_message` → `close_agent_chat` still passes locally; webapp typecheck clean.
Summary
POST /api/v1/sessionswas secret-key-only because the customer browser flow runs throughchat.createStartSessionAction(server-side, holds the secret key). But thecli-v3MCPstart_agent_chattool is itself a server-side surface — developer's CLI/IDE acting as their own server — and only holds a JWT minted from the user's PAT. Without JWT support on this route the entire MCP agent toolkit (start_agent_chat,send_agent_message,close_agent_chat) is blocked at session creation.Add
allowJWT: trueplus anauthorizationblock requiring thewrite:sessions(oradmin) super-scope.Why a wildcard
sessionsresourceResource scoping by
taskIdentifierisn't possible at auth-resolve time — action routes don't passbodyto theresourcecallback, and the task name only lives in the body. So the resource issessions: "*"and the super-scope does the actual gating. The JWT-issuer (cli-v3 MCP, customer servers wrapping their own auth helpers, etc.) decides which scopes to mint, which is where per-task narrowing lives.Test plan
mcp__trigger__start_agent_chat→send_agent_message("pong")→send_agent_message("echo")→close_agent_chatall succeed. Two assistant turns reuse the same runId (continuation in the idle window).chat.createStartSessionActionflow continues to work unchanged (still uses secret-key path under the hood).Notes
This unblocks T17 in the ai-chat e2e smoke catalog (which lives in the feature branch's skill catalog, not this repo). Pairs with the cli-v3 MCP fix on the feature branch (
feat: AI SDK custom useChat transport & chat.task harness, PR #3173) — that PR'sagentChat.tschange makes the call shape correct (taskIdentifier+triggerConfig); this PR opens the door for the JWT to actually pass.